package com.test.config.granteConfig;

import com.test.dao.ResourceMapper;
import com.test.entity.pojo.Resource;
import com.test.service.IResourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @ClassName MySecurityMetadataSource
 * @Discription TODO
 * @Author DaiFuqiang
 * @Date 2022/11/19 22:31
 */
@Component
public class MySecurityMetadataSource implements SecurityMetadataSource {
    /**
     * 当前系统所有接口资源对象，放在这里相当于一个缓存的功能。
     * 你可以在应用启动时将该缓存给初始化，也可以在使用过程中加载数据，这里我就不多展开说明了
     */
    private static final Set<Resource> RESOURCES = new HashSet<>();

    @Autowired
    private IResourceService resourceService;

    @Autowired
    private ResourceMapper resourceMapper;

//    {
//        initResoucce();
//    }

    private void initResoucce() {
        List<Resource> list = resourceService.list();
        list.stream().forEach(x -> RESOURCES.add(x));
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) {
        // 该对象是Spring Security帮我们封装好的，可以通过该对象获取request等信息
        FilterInvocation filterInvocation = (FilterInvocation) object;
        HttpServletRequest request = filterInvocation.getRequest();

//        刚开始是想在 对象初始化的时候初始化 RESOURCES，但是这个时候 resourceService 还没有注入进来，所以在代码块写初始化方法会报错
        if (RESOURCES.size() == 0) {
            initResoucce();
        }
        // 遍历所有权限资源，以和当前请求进行匹配
        for (Resource resource : RESOURCES) {
            // 因为我们url资源是这种格式：GET:/API/user/test/{id}，冒号前面是请求方法，冒号后面是请求路径，所以要字符串拆分
            String[] split = resource.getPath().split(":");
            // 因为/API/user/test/{id}这种路径参数不能直接equals来判断请求路径是否匹配，所以需要用Ant类来匹配
            AntPathRequestMatcher ant = new AntPathRequestMatcher(split[1]);
            // 如果请求方法和请求路径都匹配上了，则代表找到了这个请求所需的权限资源
            if (request.getMethod().equals(split[0]) && ant.matches(request)) {
                // 将我们权限资源id返回，这个SecurityConfig就是ConfigAttribute一个简单实现
                return Collections.singletonList(new SecurityConfig(resource.getId().toString()));
            }
        }
        // 走到这里就代表该请求无需授权即可访问，返回空
        return null;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        // 不用管，这么写就行
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        // 不用管，这么写就行
        return true;
    }
}

